package com.gitee.ly.ymorm.executor;

import com.gitee.ly.ymorm.YmOrmConfig;
import com.gitee.ly.ymorm.exceptions.YmOrmException;
import com.gitee.ly.ymorm.log.YmOrmLog;
import com.gitee.ly.ymorm.log.YmOrmLogFactory;
import com.gitee.ly.ymorm.mapping.ParamMap;
import com.gitee.ly.ymorm.mapping.YmOrmStatement;
import com.gitee.ly.ymorm.transaction.Transaction;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

/**
 * BaseExecutor
 *
 * @author ly
 **/
public abstract class BaseExecutor implements Executor {
    private YmOrmLog log = YmOrmLogFactory.getLog(this.getClass());
    protected Executor wrapper;
    private YmOrmConfig configuration;
    protected Transaction transaction;
    private boolean closed;

    public BaseExecutor(YmOrmConfig configuration, Transaction transaction) {
        this.configuration = configuration;
        this.transaction = transaction;
        this.closed = false;
        this.wrapper = this;
    }

    @Override
    public int update(YmOrmStatement ymOrmStatement, ParamMap paramMap) throws SQLException {
        return doUpdate(ymOrmStatement, paramMap);
    }

    @Override
    public <E> List<E> query(YmOrmStatement ymOrmStatement, ParamMap paramMap, Class<? extends E> resultType) throws SQLException {
        return doQuery(ymOrmStatement, paramMap, resultType);
    }

    protected abstract int doUpdate(YmOrmStatement ymOrmStatement, ParamMap paramMap) throws SQLException;

    protected abstract <E> List<E> doQuery(YmOrmStatement ymOrmStatement, ParamMap paramMap, Class<? extends E> resultType) throws SQLException;

    protected void closeStatement(Statement statement) {
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                // ignore
            }
        }
    }

    @Override
    public void commit(boolean required) throws SQLException {
        if (closed) {
            throw new YmOrmException("Cannot commit, transaction is already closed");
        }
        if (required) {
            transaction.commit();
        }
    }

    @Override
    public void rollback(boolean required) throws SQLException {
        if (!closed) {
            if (required) {
                transaction.rollback();
            }
        }
    }

    @Override
    public Transaction getTransaction() {
        if (closed) {
            throw new YmOrmException("Executor was closed. getTransaction error");
        }
        return transaction;
    }

    protected Connection getConnection(YmOrmLog log) throws SQLException {
        Connection connection = transaction.getConnection();
        return connection;
    }

    @Override
    public void close(boolean forceRollback) {
        try {
            try {
                rollback(forceRollback);
            } finally {
                if (transaction != null) {
                    transaction.close();
                }
            }
        } catch (SQLException e) {
            log.error("Unexpected exception on closing transaction.  Cause: " + e);
        } finally {
            transaction = null;
            closed = true;
        }
    }

    @Override
    public boolean isClosed() {
        return closed;
    }
}
